package com.xingda.packing.dmss.minitor.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xingda.packing.dmss.config.appset.AppSetParam;
import com.xingda.packing.dmss.enums.WheelFinishedState;
import com.xingda.packing.dmss.enums.WheelQualityState;
import com.xingda.packing.dmss.minitor.entity.PkDownWheel;
import com.xingda.packing.dmss.minitor.entity.PkWheel;
import com.xingda.packing.dmss.minitor.mapper.PkDownWheelMapper;
import com.xingda.packing.dmss.minitor.mapper.PkWheelMapper;
import com.xingda.packing.dmss.minitor.service.IPkDownWheelService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Service
public class PkDownWheelServiceImpl extends ServiceImpl<PkDownWheelMapper, PkDownWheel> implements IPkDownWheelService {
    @Resource
    private PkWheelMapper pkWheelMapper;
    private static final List<String> torqueInterval = Arrays.asList("-3.0", "-2.75", "-2.5", "-2.0", "-1.75", "-1.5",
            "-1.25", "-1.0", "-0.75", "-0.5", "-0.25", "0.0", "0.25", "0.5", "0.75", "1.0", "1.25", "1.5", "1.75",
            "2.0", "2.25", "2.5", "2.75", "3");

    @Override
    public List<JSONObject> getStatisticsInfo() {
        List<JSONObject> list = new ArrayList<>();
        LambdaQueryWrapper<PkDownWheel> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(PkDownWheel::getIsFinished, WheelFinishedState.FINISHED.getCode())
                .eq(PkDownWheel::getQualifiedState, WheelQualityState.QUALITY.getCode())
                .likeRight(PkDownWheel::getBarCode, "XC");
        Map<String, List<PkDownWheel>> collect = this.list(queryWrapper).stream().collect(Collectors.groupingBy(PkDownWheel::getConsumerName));
        collect.forEach((consumerName, pkDownWheelList) -> {

            JSONObject torqueJson = new JSONObject();
            for (PkDownWheel pkDownWheel : pkDownWheelList) {
                BigDecimal torqueValue = pkDownWheel.getTorqueValue();
                // 扭转值作为key,获得该扭转值的个数
                String key = String.valueOf(torqueValue.doubleValue());
                int count = torqueJson.getIntValue(key);
                count++;
                torqueJson.put(key, count);
            }
            List<Integer> torqueCount = torqueInterval.stream()
                    .map(torque -> torqueJson.getInteger(torque) == null ? 0 : torqueJson.getInteger(torque))
                    .collect(Collectors.toList());

            double sum = pkDownWheelList.stream().map(PkDownWheel::getTorqueValue).mapToDouble(BigDecimal::doubleValue)
                    .sum();
            OptionalDouble avg = pkDownWheelList.stream().map(PkDownWheel::getTorqueValue)
                    .mapToDouble(BigDecimal::doubleValue).average();

            JSONArray statisticsArray = new JSONArray();
            JSONObject consumer = new JSONObject();
            consumer.put("desc", "客户");
            consumer.put("value", consumerName);
            statisticsArray.add(consumer);

            JSONObject total = new JSONObject();
            total.put("desc", "总轮数");
            total.put("value", pkDownWheelList.size());
            statisticsArray.add(total);

            JSONObject sumTorque = new JSONObject();
            sumTorque.put("desc", "总轮扭转和");
            sumTorque.put("value", sum);
            statisticsArray.add(sumTorque);

            JSONObject avgTorque = new JSONObject();
            avgTorque.put("desc", "轮扭转平均值");
            BigDecimal avgValue = BigDecimal.valueOf(avg.isPresent() ? avg.getAsDouble() : 0.0)
                    .setScale(4, RoundingMode.HALF_UP);
            avgTorque.put("value", avgValue.doubleValue());
            statisticsArray.add(avgTorque);

            JSONObject avgTorque12Json = new JSONObject();
            avgTorque12Json.put("desc", "层轮扭转平均和");
            BigDecimal avgValue12 = avgValue.multiply(BigDecimal.valueOf(12));
            avgTorque12Json.put("value", avgValue12.doubleValue());
            statisticsArray.add(avgTorque12Json);

            JSONObject standardDiviation = new JSONObject();
            standardDiviation.put("desc", "扭转标准差");
            standardDiviation.put("value", BigDecimal.valueOf(StandardDiviation(pkDownWheelList.stream().map(PkDownWheel::getTorqueValue)
                            .mapToDouble(BigDecimal::doubleValue).toArray()))
                    .setScale(4, RoundingMode.HALF_UP).doubleValue());
            statisticsArray.add(standardDiviation);

            JSONObject categoryJson = new JSONObject();
            categoryJson.put("xAxis.data", torqueInterval);
            categoryJson.put("yAxis.data", torqueCount);
            JSONObject resultJson = new JSONObject();
            resultJson.put("category", categoryJson);
            //resultJson.put("downWheels", pkDownWheelList);
            resultJson.put("statistics", statisticsArray);
            list.add(resultJson);
        });
        return list;
    }

    // 标准差σ=sqrt(s^2)
    private double StandardDiviation(double[] x) {
        int m = x.length;
        if (m == 0) {
            return 0;
        }
        double sum = 0;
        for (double v : x) {// 求和
            sum += v;
        }
        double dAve = sum / m;// 求平均值
        double dVar = 0;
        for (double v : x) {// 求方差
            dVar += (v - dAve) * (v - dAve);
        }
        return Math.sqrt(dVar / m);
    }

    @Override
    public void removeMinuteAgo() {
        //删除八小时之前的数据
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MINUTE, -AppSetParam.delete_down_wheel_minute_ago);
        LambdaQueryWrapper<PkDownWheel> pkDownWheeLambdaQueryWrapper = Wrappers.lambdaQuery();
        pkDownWheeLambdaQueryWrapper.lt(PkDownWheel::getDownTime, cal.getTime());
        remove(pkDownWheeLambdaQueryWrapper);
    }

    @Override
    public void removePacking() {
        List<PkDownWheel> pkDownWheelList = this.list();
        LambdaQueryWrapper<PkWheel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(PkWheel::getBarCode, pkDownWheelList.stream().map(PkDownWheel::getBarCode).collect(Collectors.toList()));
        List<String> collect = pkWheelMapper.selectList(lambdaQueryWrapper).stream().map(PkWheel::getBarCode).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            LambdaQueryWrapper<PkDownWheel> pkDownWheeLambdaQueryWrapper = Wrappers.lambdaQuery();
            pkDownWheeLambdaQueryWrapper.in(PkDownWheel::getBarCode, collect);
            remove(pkDownWheeLambdaQueryWrapper);
        }
    }
}
